import { Asset, native, sys } from "cc";
import { EventManager } from "./EventManager";
import { Logger } from "./Logger";
import VersionManager from "./VersionManager";

export default class HotUpdate {

    public static Event_CheckUpdate: string = "Event_CheckUpdate";

    public static Event_On_Progress: string = "HotUpdate_Event_On_Progress";
    public static Event_On_NeedUpdate: string = "HotUpdate_Event_On_NeedUpdate";
    public static Event_Finish_Update: string = "HotUpdate_Event_Finish";
    public static Event_On_ALREADY_UP_TO_DATE: string = "HotUpdate_Event_On_ALREADY_UP_TO_DATE";
    public static Event_On_Fail_Update: string = "HotUpdate_Event_On_Fail_Update";

    private _am: native.AssetsManager;
    private storagePath: string;
    private localVersion: string;
    private remoteVersion: string;


    public needUpdate: boolean = false;
    public isUpdating: boolean;
    public isFinishUpdate: boolean;
    public isCheck: boolean;
    public key: string;
    private hotupdateIndex: number;

    private manifest: Asset; //本地project.manifest资源清单文件


    constructor() {
    }

    public init(index: number, key: string = "Code-remote-asset", manifest: Asset) {
        this.manifest = manifest
        if (sys.isNative) {
            this.hotupdateIndex = index;
            this.key = key;
            this.storagePath = native.fileUtils.getWritablePath() + key;
            if (!native.fileUtils.isDirectoryExist(this.storagePath)) {
                native.fileUtils.createDirectory(this.storagePath)
            }
        }
        this.needUpdate = false;
        this.isUpdating = false;
        this.isFinishUpdate = false;
        this.isCheck = false;
        Logger.log("HotUpdate.init==", manifest)
    }

    private jumpToPackUpate() {
        VersionManager.instance.jumpToPackUpate()
    }

    //显示强制更新，即更细包面板
    private showPackUpdateDialog() {
        // DialogTips.show((isOk: boolean) => {
        this.jumpToPackUpate();
        //     this.showPackUpdateDialog();
        // }, DialogTips.DialogTips_Type_Sure, "有新的版本需要更新，下载后请先卸载，以前的版本，再安装！");
    }

    private checkNeedVerson() {
        if (this.localVersion == this.remoteVersion) {
            this.alreadyUpToDate();
        } else {
            Logger.log("new version found, please try to update======hotupdate=", this.localVersion, this.remoteVersion);
            this.needUpdate = true;
            this.isUpdating = false
            this.isCheck = false
            EventManager.instance.dispatch(HotUpdate.Event_On_NeedUpdate, this.key);
        }
    }

    private checkCb(event) {
        Logger.log('checkCb Code: =================' + event.getEventCode());
        switch (event.getEventCode()) {
            case native.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                Logger.log("No local manifest file found, hot update skipped.");
                this.failUpdate();
                break;
            case native.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case native.EventAssetsManager.ERROR_PARSE_MANIFEST:
                Logger.log("Fail to download manifest file, hot update skipped.");
                this.failUpdate();
                break;
            case native.EventAssetsManager.ALREADY_UP_TO_DATE:
                Logger.log("Already up to date with the latest remote version.");
                // this.finishUpdate(false);
                this.alreadyUpToDate();
                break;
            case native.EventAssetsManager.NEW_VERSION_FOUND:
                Logger.log("new version found, please try to update.", this.localVersion, this.remoteVersion);
                this.checkNeedVerson()
                break;
            case native.EventAssetsManager.UPDATE_PROGRESSION:
                // var currentPercent = event.getPercent();
                // var totalPercent = event.getPercentByFile();
                // Logger.log("UPDATE_PROGRESSION==========", currentPercent, totalPercent);
                // var fileprocess = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
                // var byteprocess = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();
                Logger.log("UPDATE_PROGRESSION2222==========", this.key, event.getDownloadedBytes(), event.getTotalBytes());
                // Logger.log("UPDATE_PROGRESSION3333==========", fileprocess, byteprocess);
                if (event.getTotalBytes() > 0) {
                    EventManager.instance.dispatch(HotUpdate.Event_On_Progress, event.getDownloadedBytes(), event.getTotalBytes(), this.key)
                }
                break;
            case native.EventAssetsManager.UPDATE_FINISHED:
                Logger.log("UPDATE_FINISHED==============");
                this.finishUpdate(true);
                break;
            case native.EventAssetsManager.UPDATE_FAILED:
                Logger.log("Update failed==========", event.getMessage());
                this.failUpdate();
                break;
            case native.EventAssetsManager.ERROR_UPDATING:
                let fullFilePath: string = this.storagePath + "/" + event.getAssetId();
                let tempFilePath: string = this.storagePath + "_temp/" + event.getAssetId();
                Logger.log("fullFilePath====", fullFilePath);
                Logger.log("tempFilePath====", tempFilePath);
                Logger.log("ERROR_UPDATING=============", event.getAssetId(), event.getMessage());
                this.failUpdate();
                break;
            default:
                // this.failUpdate();
                return;
        }
    }

    public checkUpdate() {
        if (this.isUpdating || this.isCheck) {
            Logger.log("checkUpdate ...", this.isUpdating, this.isFinishUpdate, this.isCheck, this.key);
            return;
        }
        Logger.log("checkUpdate .22..", this.isUpdating, this.isFinishUpdate, this.isCheck, this.key)
        let hotupdateUrlKey: string = VersionManager.Config_Key[this.hotupdateIndex];
        // Logger.log("checkoutUpdate=====", this.manifestUrl, hotupdateUrlKey);
        if (!this._am) {
            this._am = new native.AssetsManager('', this.storagePath, this.versionCompareHandle.bind(this));
        }
        // this._am.setMaxConcurrentTask(1);

        this._am.setVerifyCallback(function (filePath, asset) {
            return true;
        });
        this._am.setEventCallback(this.checkCb.bind(this));
        // 设置事件回调
        this.isCheck = true;
        let manifest: native.Manifest = new native.Manifest(this.manifest.nativeAsset, this.storagePath);
        this._am.loadLocalManifest(manifest, this.storagePath);
        this._am.checkUpdate();
    }

    /**
     * @param versionA 本地版本 1.0.0.0
     * @param versionB 服务器版本 1.0.1.1
     * @param return -1需要更新 不用更新
     */
    private versionCompareHandle(versionA, versionB) {
        var vA = versionA.split('.');
        var vB = versionB.split('.');
        this.localVersion = versionA;
        this.remoteVersion = versionB
        Logger.log("versionCompareHandle======", this.key, VersionManager.Config_Key[0], versionA, versionB);
        if (this.key == VersionManager.Config_Key[0]) {
            Logger.log("versionCompareHandle22===", versionA, versionB);
            VersionManager.instance.nowVersion = versionA;
            VersionManager.instance.targetVersion = versionB;
        }
        for (var i = 0; i < vA.length; ++i) {
            var a = parseInt(vA[i]);
            var b = parseInt(vB[i] || 0);
            if (a === b) {
                continue;
            }
            else {
                return a - b;
            }
        }
        if (vB.length > vA.length) {
            return -1;
        }
        else {
            return 0;
        }
    }

    public startUpdate() {
        // if (this.isUpdating) return;
        let localManifest = this._am.getLocalManifest();
        let remoteManifest = this._am.getRemoteManifest();
        Logger.log("startUpdate111===", localManifest.getVersionFileUrl());
        Logger.log("startUpdate2222===", localManifest.getManifestFileUrl());
        Logger.log("startUpdate3333===", remoteManifest.getVersionFileUrl());
        Logger.log("startUpdate4444===", remoteManifest.getManifestFileUrl());
        this.isUpdating = true;
        EventManager.instance.dispatch(HotUpdate.Event_On_Progress, 0, 100, this.key)
        this._am.update();
    }

    public disposeUpdate() {
        if (this._am) {
            this._am.setVerifyCallback(null);
            this._am.setEventCallback(null);
        }
        this._am = null;
        this.isUpdating = false;
        this.needUpdate = false;
        this.isCheck = false
    }

    private failUpdate() {
        this.disposeUpdate();
        this.isCheck = false;
        if (this.key == VersionManager.Config_Key[0]) {
            // NetUrlManager.onFailHotUpdateDomain();
        }
        EventManager.instance.dispatch(HotUpdate.Event_On_Fail_Update, this.key);
    }

    private alreadyUpToDate() {
        Logger.log("alreadyUpToDate=", this.key)
        this.disposeUpdate();
        this.isFinishUpdate = true;
        this.isCheck = false
        EventManager.instance.dispatch(HotUpdate.Event_On_ALREADY_UP_TO_DATE, this.key);
    }

    private finishUpdate(needRestart: boolean) {
        Logger.log("更新完成=====", needRestart, this.key);
        this.disposeUpdate();
        this.isFinishUpdate = true;
        EventManager.instance.dispatch(HotUpdate.Event_Finish_Update, this.key, needRestart);
        if (needRestart) {
            var searchPaths = native.fileUtils.getSearchPaths();
            Logger.log("更新完成====searchPaths======", searchPaths);
            sys.localStorage.setItem('searchPaths', JSON.stringify(searchPaths));
            native.fileUtils.setSearchPaths(searchPaths);
            if (this.key == VersionManager.Config_Key[0]) {
                setTimeout(() => {
                    // GameController.instance.restartGame()
                }, 100);
            }
        }
    }

}